package com.kcht.np.common.jwt;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * JWT和用户信息之间的转换
 * */
@Getter
@Setter
@Component
@ConfigurationProperties(prefix = "jwt")
public class JwtTokenConverter implements Serializable {

    private static final String CLAIM_KEY_USER_ACCOUNT = "sub";

    private static final String CLAIM_KEY_CREATED = "created";

    /**
      *秘钥
      *
     */
    private String secret;

    /**
      *过期时间
     */
    private Long expiration;

    private String tokenHeader;

    private String tokenHead;

    /**
      *  从数据声明生成令牌
    */
    private String generateToken(Map<String, Object> claims) {
        Date expirationDate = new Date(System.currentTimeMillis() + expiration);
        return Jwts.builder().setClaims(claims).setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, secret).compact();
    }

    /**
      *  从令牌中获取数据声明
    */
    private Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }


    public String generateToken(JwtUser jwtUser) {
        Map<String, Object> claims = new HashMap<>(2);
        claims.put("sub", jwtUser.getUsername());
        claims.put("created", new Date());
        claims.put("authorities", new ArrayList<>(jwtUser.getAuthoritiesCol()));
        return generateToken(claims);
    }

    /**
      *  从令牌中获取用户名
    */
    public String getUsernameFromToken(String token) {
        String username;
        try {
            Claims claims = getClaimsFromToken(token);
            username = claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }


    public Authentication getAuthentication(String token){
        Authentication authentication=null;
        try{
            Claims claims = getClaimsFromToken(token);
            String username=(String)claims.get("sub");
            Collection<GrantedAuthority> authorities=((List<String>) claims.get("authorities"))
                    .stream()
                    .map(SimpleGrantedAuthority::new)
                    .collect(Collectors.toList());
            authentication = new UsernamePasswordAuthenticationToken(
                    username, null, authorities);
        }catch (Exception e) {
            e.printStackTrace();
        }
        return authentication;
    }

    /**
      *  判断令牌是否过期
    */
    public Boolean isTokenExpired(String token) {
        try {
            Claims claims = getClaimsFromToken(token);
            Date expiration = claims.getExpiration();
            return expiration.before(new Date());
        } catch (Exception e) {
            return false;
        }
    }

    /**
      *  刷新令牌
      *
    */
    public String refreshToken(String token) {
        String refreshedToken;
        try {
            Claims claims = getClaimsFromToken(token);
            claims.put("created", new Date());
            refreshedToken = generateToken(claims);
        } catch (Exception e) {
            refreshedToken = null;
        }
        return refreshedToken;
    }

    /**
      *  截取令牌
      *  截取完整的token，根据前缀 "Bearer "开头
    */
    public String interceptCompleteToken(String completeToken) {
        return completeToken.substring(this.getTokenHead().length());
    }

    /**
      *  验证令牌
    */
    public boolean validateToken(String token, UserDetails userDetails) {
        String username = getUsernameFromToken(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }
}
